package koans

class AboutInterfaces extends Koans {

    interface X {
        def f()
    }

    // Groovy provides some very convenient ways to implement interfaces
    void testInterfaceWithSingleMethodCanBeImplementedAsClosure() {
        def x = { "string" } as X
        assert __ == x.f()
    }

    void testCallingNonexistentMethodThrowsMissingMethodException() {
        def x = { "string" } as X
        try {
            x.g() // this is a "missing method" in interface X
        } catch (e) {
            // Change __ to the appropriate truth value
            assert __ == (MissingMethodException == e.class)
        }
    }

    void testInterfaceCanBeImplementedAsMap() {
        def x = [
            f: { "string" }
        ] as X 
        assert __ == x instanceof X // Change __ to the appropriate truth value
        assert __ == x.f()
    }

    void testNonexistentMapMethodsAreUnsupported() {
        def x = [:] as X
        try {
            x.f()
        } catch (e) {
            // Change __ to the appropriate truth value
            assert __ == (UnsupportedOperationException == e.class)
        } 
    }

    interface Y {
        def g(int n)
        def h(String s, int n)
    }


    void testInterfaceWithMultipleMethodsCanBeImplementedAsClosure() {
        // Since you need a closure whose parameter list matches that of all the methods,
        // you would typically use an array as the sole parameter.
        def y = { Object[] args -> args } as Y

        assert __ == y instanceof Y // Change __ to the appropriate truth value
        assert __ == y.g(42)
        assert __ == y.h("hello", 137)
    }

    void testClosureParametersMustMatchAllMethodSignatures() {
        def y = { int n -> n } as Y
        assert __ == y.g(42)
        try {
            y.h("hello", 137)  
        } catch (e) {
            // Change __ to the appropriate truth value
            assert __ == (MissingMethodException == e.class)
        }
    }

    void testInterfaceWithMultipleMethodsCanBeImplementedAsMap() {
        def y = [
            g: { it * 2 },
            h: { s, n -> "${s} ${n}" }
        ] as Y
        assert __ == y instanceof Y // Change __ to the appropriate truth value
        assert __ == y.g(7)
        assert __ == y.h("hello", 137)
    }

}
